#include <mysql/mysql.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <list>
#include <pthread.h>
#include <iostream>
#include "sql_connection_pool.h"

using namespace std;

connection_pool::connection_pool(){
    m_Curconn = 0;
    m_Freeconn = 0;
}

connection_pool* connection_pool::GetInstance(){
    static connection_pool connPool;
    return &connPool;
}

//构造初始化
void connection_pool::init( string url, string User, string PassWord, string DataBaseName, int Port, int MaxConn, int close_log){
    m_url = url;
    m_port = Port;
    m_user = User;
    m_password = PassWord;
    m_databasename = DataBaseName;
    m_close_log = close_log;

    for(int i = 0; i < MaxConn; i++){
        MYSQL* con = NULL;
        con = mysql_init(con);

        if( con == NULL ){
            LOG_ERROR( "MySQL Error");
            exit(1);
        }
        con = mysql_real_connect( con, url.c_str(), User.c_str(),PassWord.c_str(),DataBaseName.c_str(),Port, NULL,0);

        if( con == NULL ){
            LOG_ERROR( "MySQL Error");
            exit(1);
        }
        connList.push_back( con );
        ++m_Freeconn;

        m_sem = sem( m_Freeconn );

        m_maxconn = m_Freeconn;    
    }
}
//当有请求时，从数据库连接池中返回一个可用连接，更新使用和空闲连接数
MYSQL* connection_pool:: GetConnection(){
    MYSQL* con = NULL;

    if( connList.size() == 0 ){
        return NULL;
    }

    m_sem.wait();

    m_lock.lock();
    con = connList.front();
    connList.pop_front();

    --m_Freeconn;
    ++m_Curconn;

    m_lock.unlock();

    return con;
}

bool connection_pool:: ReleaseConnection( MYSQL *con ){
    if( con == NULL ){
        return false;
    }
    
    m_lock.lock();
    connList.push_back(con);
    ++m_Freeconn;
    --m_Curconn;
    m_lock.unlock();

    m_sem.post();
    return true;
}

void connection_pool::DestroyPool(){
    m_lock.lock();
    if( connList.size() > 0 ){
        for(std::list<MYSQL*>::iterator iter = connList.begin(); iter != connList.end(); iter++ ){
            MYSQL* con = *iter;
            mysql_close( con );
        }
        m_Curconn = 0;
        m_Freeconn = 0;
        connList.clear();
    }
    m_lock.unlock();
}

int connection_pool::GetFreeConn(){
    return this->m_Freeconn;
}

connection_pool::~connection_pool(){
    DestroyPool();
}

connectionRAII::connectionRAII( MYSQL**SQL, connection_pool * connPool ){
    *SQL = connPool->GetConnection();

    conRAII = *SQL;
    poolRAII = connPool;
}

connectionRAII::~connectionRAII(){
    poolRAII->ReleaseConnection(conRAII);
}
